package com.wanban.downloader.utils

import android.net.Uri
import android.text.TextUtils
import com.blankj.utilcode.util.ConvertUtils
import com.blankj.utilcode.util.NumberUtils
import java.io.BufferedReader
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URL
import java.util.Arrays
import java.util.regex.Pattern


object CommonUtils {

    fun getM3U8AbsoluteUrl(videoUrl: String?, line: String?): String {
        if (TextUtils.isEmpty(videoUrl) || TextUtils.isEmpty(line)) {
            return ""
        }
        if (videoUrl!!.startsWith("file://") || videoUrl.startsWith("/")) {
            return videoUrl
        }
        val baseUriPath = getBaseUrl(videoUrl)
        var hostUrl = getHostUrl(videoUrl)
        if (line?.startsWith("//") == true) {
            return getSchema(videoUrl) + ":" + line
        }
        if (line?.startsWith("/") == true) {
            val pathStr = getPathStr(videoUrl)
            val longestCommonPrefixStr = getLongestCommonPrefixStr(pathStr, line)
            if (hostUrl.endsWith("/")) {
                hostUrl = hostUrl.substring(0, hostUrl.length - 1)
            }
            return hostUrl + longestCommonPrefixStr + line.substring(longestCommonPrefixStr.length)
        }
        return if (line?.startsWith("http") == true) {
            line
        } else baseUriPath + line
    }

    private fun getSchema(url: String): String {
        if (TextUtils.isEmpty(url)) {
            return ""
        }
        val index = url.indexOf("://")
        return if (index != -1) {
            url.substring(0, index)
        } else ""
    }

    /**
     * 例如https://xvideo.d666111.com/xvideo/taohuadao56152307/index.m3u8
     * 我们希望得到https://xvideo.d666111.com/xvideo/taohuadao56152307/
     *
     * @param url
     * @return
     */
    fun getBaseUrl(url: String): String {
        if (TextUtils.isEmpty(url)) {
            return ""
        }
        val slashIndex = url.lastIndexOf("/")
        return if (slashIndex != -1) {
            url.substring(0, slashIndex + 1)
        } else url
    }

    /**
     * 例如https://xvideo.d666111.com/xvideo/taohuadao56152307/index.m3u8
     * 我们希望得到https://xvideo.d666111.com/
     *
     * @param url
     * @return
     */
    fun getHostUrl(url: String): String {
        return if (TextUtils.isEmpty(url)) {
            ""
        } else try {
            val formatURL = URL(url)
            val host = formatURL.host ?: return url
            val hostIndex = url.indexOf(host)
            if (hostIndex != -1) {
                val port = formatURL.port
                val resultUrl = if (port != -1) {
                    url.substring(0, hostIndex + host.length) + ":" + port + "/"
                } else {
                    url.substring(0, hostIndex + host.length) + "/"
                }
                return resultUrl
            }
            url
        } catch (e: java.lang.Exception) {
            url
        }
    }


    fun parseStringAttr(line: String, pattern: Pattern): String? {
        val matcher = pattern.matcher(line)
        return if (matcher.find() && matcher.groupCount() == 1) {
            matcher.group(1)
        } else null
    }


    /**
     * 例如https://xvideo.d666111.com/xvideo/taohuadao56152307/index.m3u8
     * 我们希望得到   /xvideo/taohuadao56152307/index.m3u8
     *
     * @param url
     * @return
     */
    fun getPathStr(url: String): String {
        if (TextUtils.isEmpty(url)) {
            return ""
        }
        val hostUrl = getHostUrl(url)
        return if (TextUtils.isEmpty(hostUrl)) {
            url
        } else url.substring(hostUrl.length - 1)
    }

    fun closeConnection(connection: HttpURLConnection?) {
        connection?.disconnect()
    }

    fun isM3U8Mimetype(mimeType: String): Boolean {
        return !TextUtils.isEmpty(mimeType) &&
                (mimeType.contains(Constants.MIME_TYPE_M3U8_1) ||
                        mimeType.contains(Constants.MIME_TYPE_M3U8_2) ||
                        mimeType.contains(Constants.MIME_TYPE_M3U8_3) ||
                        mimeType.contains(Constants.MIME_TYPE_M3U8_4) ||
                        mimeType.contains(Constants.MIME_TYPE_M3U8_5))
    }

    fun parseMultiStringAttr(line: String, pattern: Pattern): String? {
        val matcher = pattern.matcher(line)
        if (matcher.find()) {
            val count = matcher.groupCount()
            for (index in 0 until count) {
                if (matcher.group(index) != null) {
                    return matcher.group(index)
                }
            }
        }

        return if (matcher.find() && matcher.groupCount() == 1) {
            matcher.group(1)
        } else null
    }

    fun parseOptionalStringAttr(line: String, pattern: Pattern): String? {
        val matcher = pattern.matcher(line)
        return if (matcher.find()) matcher.group(1) else null
    }

    // 检查m3u开头是否是空白
    @Throws(IOException::class)
    fun checkM3UHeader(reader: BufferedReader): Boolean {
        var last = reader.read()
        if (last == 0xEF) {
            if (reader.read() != 0xBB || reader.read() != 0xBF) {
                return false
            }
            // The playlist contains a Byte Order Mark, which gets discarded.
            last = reader.read()
        }
        last = skipIgnorableWhitespace(reader, true, last)
        val playlistHeaderLength = Constants.TAG_PLAYLIST_HEADER.length
        for (i in 0 until playlistHeaderLength) {
            if (last != Constants.TAG_PLAYLIST_HEADER[i].code) {
                return false
            }
            last = reader.read()
        }
        last = skipIgnorableWhitespace(reader, false, last)
        return isLinebreak(last)
    }

    @Throws(IOException::class)
    private fun skipIgnorableWhitespace(reader: BufferedReader, skipLinebreaks: Boolean, c: Int): Int {
        var localC = c
        while (localC != -1 && Character.isWhitespace(localC) && (skipLinebreaks || !isLinebreak(localC))) {
            localC = reader.read()
        }
        return localC
    }

    private fun isLinebreak(c: Int): Boolean {
        return c == '\n'.code || c == '\r'.code
    }

    /**
     * 获取两个字符串的最长公共前缀
     * /xvideo/taohuadao56152307/500kb/hls/index.m3u8   与     /xvideo/taohuadao56152307/index.m3u8
     *
     *
     * /xvideo/taohuadao56152307/500kb/hls/jNd4fapZ.ts  与     /xvideo/taohuadao56152307/500kb/hls/index.m3u8
     *
     * @param str1
     * @param str2
     * @return
     */
    fun getLongestCommonPrefixStr(str1: String, str2: String): String {
        if (TextUtils.isEmpty(str1) || TextUtils.isEmpty(str2)) {
            return ""
        }
        if (TextUtils.equals(str1, str2)) {
            return str1
        }
        val arr1 = str1.toCharArray()
        val arr2 = str2.toCharArray()
        var j = 0
        while (j < arr1.size && j < arr2.size) {
            if (arr1[j] != arr2[j]) {
                break
            }
            j++
        }
        return str1.substring(0, j)
    }

    fun matchHttpSchema(url: String?): Boolean {
        if (TextUtils.isEmpty(url)) return false
        val uri = Uri.parse(url)
        val schema = uri.scheme
        return "http" == schema || "https" == schema
    }


    fun getFormatSpeedString(speed: Long): String{
        return ConvertUtils.byte2FitMemorySize(speed, 2) + "/s"
    }

    fun getFormatPercentString(percent: Float): String{
        return NumberUtils.format(percent, 2) + "%"
    }

    fun map2String(map: Map<String, String>?): String?{
        if (map == null) return null
        //将set集合转换为数组
        val keyArray = map.keys.toTypedArray()
        //给数组排序(升序)
        Arrays.sort(keyArray)
        //因为String拼接效率会很低的，所以转用StringBuilder
        val sb = StringBuilder()
        for (i in keyArray.indices) {
            // 参数值为空，则不参与签名 这个方法trim()是去空格
            val key = keyArray[i]
            val value = map[key]?.trim()
            if (!TextUtils.isEmpty(value)) {
                sb.append(key)
                sb.append(":")
                sb.append(value)
            }
            if (i != keyArray.size - 1) {
                sb.append(",")
            }
        }
        return sb.toString()
    }

    fun string2Map(str: String?): HashMap<String, String>? {
        if (str == null || TextUtils.isEmpty(str)) return null
        //根据逗号截取字符串数组
        val mapStr = str.split(",")
        //创建Map对象
        val map = HashMap<String, String>()
        //循环加入map集合
        //循环加入map集合
        for (i in mapStr.indices) {
            //根据":"截取字符串数组
            val keyValueArray = mapStr[i].split(":")
            if (keyValueArray.size < 2) continue
            //str2[0]为KEY,str2[1]为值
            map[keyValueArray[0]] = keyValueArray[1]
        }
        return map
    }
}